const { sqlCheckType, err_reply, success_reply, success_reply2 } = require('../types/type.js') // 引入枚举类型、响应

var dbConfig = require('../../util/dbconfig.js') // 引入dbconfig
const { json } = require('express')

// 引入数据格式化函数
const { format_menuListData, sortUpdate, JSSToString, sortDefault, flattenTree } = require('./jss_math.js')

const { validateLoginState } = require('../base/base_validate.js') // 登录校验
const dbconfig = require('../../util/dbconfig.js')
const { check_if_exists } = require('../other/other_request.js')

//  请求err格式：
// {
//   "code": "ER_BAD_NULL_ERROR", 
//   "errno": 1048, 
//   "sqlMessage": "Column 'tag' cannot be null", 
//   "sqlState": "23000", 
//   "index": 0, 
//   "sql": "INSERT INTO `menu`(menu_name, tag, parent_id, menu_type, permissions_role_ids, create_time) VALUES ('11', NULL, NULL, NULL, '3、2', NOW());"
// }

/** 
 * @description 1、菜单新增
 * */ 
const menu_add = async function (req, res, next) {

   // 1、校验登录状态
   const validateLogin = await validateLoginState(res, req, 'post', 'menu_add')

   if (!validateLogin) return

  // err_reply('menu/add', res, '菜单新增接口，开发中')

  const menu_name = req.body.menu_name //部门名
  const tag = req.body.tag //部门表示, 比如‘system-manager/user’
  const parent_id = req.body.parent_id ?? 0 // 上级部门ID
  const menu_type = req.body.menu_type // 菜单的排序号，比如：5-2 表示上级菜单是一级菜单里的第5个，它属于其下第二个
  let per_role_ids = req.body.permissions_role_ids // 哪些角色ID被授权可以访问, 这里拿到的是数组
  console.log('menu_add  请求参数-- ' + JSON.stringify(req.body))
  /** 
   * 判断permissions_role_ids类型
   * 
   * 1、如果是数组，转字符串，逗号拼接
   * 2、如果是字符串，什么也不做
   * 3、如果是其它类型，那就传空字符串
   */
  if (Array.isArray(per_role_ids)) per_role_ids = per_role_ids.join('、')
  else if (typeof per_role_ids == 'string') null
  else  per_role_ids = ''
  // console.log(req.body)
  // return

  // INSERT INTO `menu`(menu_name, tag, parent_id, menu_type, permissions_role_ids, create_time) VALUES ('闲谈杂记','/product-center/zatan', '10002', '2-3', '12', NOW());
  const sql_add = 'INSERT INTO `menu`(menu_name, tag, parent_id, menu_type, permissions_role_ids, create_time) VALUES (?, ?, ?, ?, ?, NOW());'
  const sqlParamters = [menu_name, tag, parent_id, menu_type, per_role_ids]
  console.log('正在查重……')
  const [check_repeate, data] = await check_if_exists('menu', 'menu_name', menu_name, res, 'menu/add')

  if(check_repeate == sqlCheckType.True) {
    console.log('查重结束～～该菜单已经存在！')
    err_reply('menu/add', res, '该菜单已经存在！')
  } else {
    // console.log('查重结束～～数据不存在，可以插入')
    dbConfig.sqlConnect(sql_add, sqlParamters, (err, data) => {
      if(err) {
        console.log('新增出错')
        console.log('打印查询语句' + JSON.stringify(sql_add))
        console.log(JSON.stringify(err))
        err_reply('menu/add', res, err.sqlMessage)
      } else{
        console.log('新增成功')
        console.log(data)
        if (!data.insertId || data.insertId.length == 0){
          console.log(`${depart_name}，该新增的菜单ID为空`)
          // 响应客户端请求
          err_reply('/menu/add',res,`${depart_name}，该菜单新增请求异常`)
          return
        }
        // 响应客户端请求
        success_reply('menu/add', res, '菜单新增成功！', data.insertId ?? '')
      }
    })
  }
}


/** 
 * @description 2、菜单删除
 * */ 
const menu_delete = async (req, res) => {
  console.log("req.body.params: " + JSON.stringify(req.body.params))

  // 1、校验登录状态
  const validateLogin = await validateLoginState(res, req, 'post', 'menu_delete')

  if (!validateLogin) return

  console.log("req.body: " + JSON.stringify(req.body))

  // err_reply('menu/update', res, '菜单删除接口，开发中')
  
  // return

  console.log('菜单删除请求 ---')
  console.log("req.body: " + JSON.stringify(req.body))

  const delete_objs = req.body.params
  let condition = ""
  delete_objs.forEach(element => {
    const element_id = element.id.toString()
    if(condition.length === 0){
      condition = `${element_id}`
    } else {
      condition = `${condition},${element_id}`
    }
  });
  console.log('打印一下condition---' + condition)
  const sql_delete = `DELETE FROM ${`menu`} WHERE id in (${condition})`
  console.log('打印一下sql_delete---' + sql_delete)

  var callBack = (err,data) => {
    console.log("err: " + err)
    console.log("data: " + JSON.stringify(data))
    // {"fieldCount":0,"affectedRows":1,"insertId":0,"serverStatus":2,"warningCount":0,"message":"","protocol41":true,"changedRows":0}
    if (err) {
      console.log('/department/delete 请求出错了')
      // 响应客户端请求
      err_reply('/department/delete',res,`${condition}，该部门删除失败`)
      return;
    } else {
      console.log(`/department/delete 请求成功 -- 部门${condition}删除成功`)
      // 响应客户端请求
      success_reply('/dep',res,'删除成功',{})
      
      // 更新同级菜单的menu_type字段
      sortWithOtherMenus(delete_objs)
    }
  }
  dbConfig.sqlConnect(sql_delete, [], callBack)
}

// 在删除某条菜单数据后，调用本方法对同级别的菜单menu_type进行重新排序
function sortWithOtherMenus(delete_objs) {
  console.log('sortWithOtherMenus开始～～\n\n\n')
  console.log(JSON.stringify(delete_objs))
  console.log('\n\n\n')
  if(!Array.isArray(delete_objs)) {
    console.log('delete_objs不是数组啊！')
    return
  }

  let condition = ""
  delete_objs.forEach(element => {
    // const parent_id = element.parent_id.toString()
    const parent_id = JSSToString(element.parent_id, '', '@sortWithOtherMenus()')
    if(condition.length === 0){
      condition = `${parent_id}`
    } else {
      condition = `${condition},${parent_id}`
    }
  });

  // 1、先查询跟delete_id同级别的所有菜单，先取delete_obj的parent_id
  
  const sql_check = `SELECT * FROM ${`menu`}  WHERE parent_id IN (${condition})`
  console.log('sortWithOtherMenus sql---' + sql_check)
  // 2、然后按照menu_type字段重新排序，
  dbconfig.sqlConnect(sql_check, [], (err, data) => {
    if(err) {
      console.log('sortWithOtherMenus - SQL出错了～')
      console.log(JSON.stringify(err))
    } else {
      console.log('sortWithOtherMenus - SQL执行成功！！')
      console.log(JSON.stringify(data))
      data = sortUpdate(data, delete_objs, 'menu_type', 'parent_id', '-')
      console.log('\n打印最终 delete_objs----')
      console.log(data)
      // sql更新
      data.forEach(element => {
        const sql_update = `UPDATE ${`menu`} SET menu_type = '${element.menu_type}' WHERE id = ${element.id};`
        console.log('sql更新~~~sql_update: ' + sql_update)
        dbconfig.sqlConnect(sql_update, [], (err, data) => {
          if(err) {
            console.log(`id为${element.id}的数据，更新出错！`)
            console.log(err)
          } else {
            console.log(`id为${element.id}的数据，更新成功！`)
          }
        })
      });
    }
  })
  
}

/** 
 * @description 3、菜单修改
 * */ 
const menu_update = async function (req, res, next) {
  // err_reply('menu/update', res, '菜单更新接口，开发中')
  // 1、校验登录状态
  const validateLogin = await validateLoginState(res, req, 'post', 'menu_update')

  if (!validateLogin) return

  // err_reply('menu/add', res, '菜单新增接口，开发中')
  const id = req.body.id
  const menu_name = req.body.menu_name // 部门名
  const tag = req.body.tag //部门表示, 比如‘system-manager/user’
  const parent_id = req.body.parent_id // 上级部门ID
  const menu_type = req.body.menu_type // 菜单的排序号，比如：5-2 表示上级菜单是一级菜单里的第5个，它属于其下第二个
  let per_role_ids = req.body.permissions_role_ids // 哪些角色ID被授权可以访问, 这里拿到的是数组

  /** 
  * 判断permissions_role_ids类型
  * 
  * 1、如果是数组，转字符串，逗号拼接
  * 2、如果是字符串，什么也不做
  * 3、如果是其它类型，那就传空字符串
  */
  if (Array.isArray(per_role_ids)) per_role_ids = per_role_ids.join('、')
  else if (typeof per_role_ids == 'string') null
  else  per_role_ids = ''

  console.log('menu_update  请求参数-- ' + JSON.stringify(req.body))

  // 拼接参数，并加入到数组params
  var params = []
  const combinationParams = (propsName, value, arr) => {
    if (value)  arr.push([`${propsName} = '${value}'`])
  }
  combinationParams('menu_name', menu_name, params)
  combinationParams('tag', tag, params)
  combinationParams('parent_id', parent_id, params)
  combinationParams('menu_type', menu_type, params)
  combinationParams('permissions_role_ids', per_role_ids, params)
  
  console.log('params ----' + JSON.stringify(params))

  let sql_update = '' // SQL语句

  if(params.length > 0) {
    console.log('条件查询，正在拼凑sql_check～～')
    // sql_check = sql_check + ' WHERE'
    var condition = ' '
    for (let index = 0; index < params.length; index++) {
      const element = params[index];
      // 拼接WHERE条件后面的SQL语句
      if(index == 0) condition = condition + `${element[0]}`
      else condition = condition + ' , ' + `${element[0]}`
    }
    // 拼凑完整的SQL语句
    sql_update = `UPDATE ${`menu`} SET ${condition} WHERE id = ${id};`
    // console.log('打印完整更新SQL：' + sql_update)
  } else {
    err_reply('mene/update', res, '更新失败，请求参数不能为空')
    return
  }
  // 开始请求
  dbConfig.sqlConnect(sql_update, [], (err, data) => {
    if(err) {
      console.log('更新出错')
      console.log('打印查询语句' + JSON.stringify(sql_update))
      console.log(JSON.stringify(err))
      err_reply('menu/add', res, err.sqlMessage)
    } else{
      console.log('更新成功')
      console.log(data)
      if (!data.affectedRows || data.affectedRows.length == 0){
        console.log(`${menu_name}，该更新的菜单ID为空`)
        // 响应客户端请求
        err_reply('/menu/update',res,`${menu_name}，该菜单更新请求异常`)
        return
      }
      // 响应客户端请求
      success_reply('menu/update', res, '菜单更新成功！', data.changedRows ?? '')
    }
  })
}

/** 
 * @description 4、菜单查询
 * */ 
const menu_query = async function (req, res, next) {
  
  // 1、校验登录状态
  const validateLogin = await validateLoginState(res, req, 'get', 'menu_query')

  if (!validateLogin) return
  
  // 2、取出分页查询的参数
  const limit = Number(req.query.limit) ?? 1000 //限制一次查询多少条，默认1000条
  const pageIndex = Number(req.query.pageIndex) ?? 1 // 要查询第几页数据
  if (pageIndex < 0) pageIndex = 1
  const offset = (pageIndex - 1) * limit
  if (offset < 0) offset = 0

  // => 是否需要将菜单组装，输否子菜单插入父菜单的children字段下
  // 默认0，表示需要组装，-1表示不需要组装，查出来直接返回即可
  const combination = req.query.combination ?? '0'

  // 3、定义查询方法，sql作为查询条件
  const check_public = async (sql_query, res)=> {
    return new Promise((reslove) => {
      dbConfig.sqlConnect(sql_query, [], (err, data) => {
        if (err) {
          console.log('菜单查询出错啦！!')
          console.log(err)
          err_reply('menu/query', res, '菜单查询出错啦！')
          reslove([false, null])
        } else {
          // console.log('菜单查询成功!!')
          reslove([true, data])
        }
      })
    })
  }

  // 4、分页查询
  let sql_query_limit = `SELECT * FROM ${`menu`}`
  if (limit > 0 && offset >= 0) {
    // 分页查询
    sql_query_limit = sql_query_limit + ` LIMIT ${limit} OFFSET ${offset};`
  }
  // console.log('分页查询SQL：' + sql_query_limit)

  const [ result_limit, data_limit ] = await check_public( sql_query_limit,res)

  // 针对data_limit，permissions_role_ids由字符串格式 ‘1、3、7’ 转为数组
  data_limit.forEach(element => {
    const id_arr = element.permissions_role_ids?.split('、').map(Number)
    element.permissions_role_ids = id_arr
    if (element.parent_id == 0) element.parent_id = null
  });
  
  if (result_limit) console.log('菜单-分页查询成功!!')
  
  // 5、查询总个数
  const sql_query_total = `SELECT count(1)  FROM ${`menu`}`
  let total = -1
  if (limit > 0 && offset >= 0) {
    // 分页查询, 那就需要查询总个数
    const [ result_total, data_total ] = await check_public( sql_query_total,res)
    total = data_total[0]['count(1)']
    // console.log('总查询SQL：' + sql_query_limit)
    // if (result_total) console.log('查询成功!! 菜单-总个数：' + total)
  }
  
  // 6、查询当前用户的所有操作权限
  let backData = []
  if (combination != '-1') { //不等于-1，代表需要将菜单和操作权限表的数据，进行组合
    const [action_result, action_data] = await query_actionPermissions(req.query.user_id, res)
    if(action_result){
      //   console.log('按钮权限，查询成功！')
      //   console.log(JSON.stringify(action_data))
      backData = format_menuListData(action_data, data_limit, 'menu_type')
      console.log('按钮权限，查询成功！', backData)
    }
  } else {
    backData = data_limit
    // // 将数据库里的字符串 ‘1、3、7’ 转为数组
    // data_limit.forEach(element => {
    //   const id_arr = element.permissions_role_ids?.split('、').map(Number)
    //   element.permissions_role_ids = id_arr
    // });
  }
  
  
  // 7、响应客户端请求
  // if (result_limit && result_total) {
  //   // success_reply2('menu/query', res, '菜单查询成功', data_limit,'menu_type', total)
  //   // success_reply2('menu/query', res, '菜单查询成功', format_menuListData(data_limit,'menu_type'), total)
  //   success_reply2('menu/query', res, '菜单查询成功', backData, total)
  // } else {
  //   // combination
  // }
  if (limit > 0 && offset >= 0) {
    success_reply2('menu/query', res, '菜单查询成功', backData, total)
  } else {
    success_reply('menu/query', res, '菜单查询成功', backData)
  }
  
}
// 查询用户ID对应的 - 所有操作权限
async function query_actionPermissions(user_id, res) {
  return new Promise((reslove) => {
    const sql_check = `SELECT tb1.* FROM
    (SELECT * ,CONCAT('、', permissions_role_ids, '、') AS permissions_role_ids_deal
    FROM ${`actionPermissions`}) AS tb1
    
    WHERE permissions_role_ids_deal LIKE 
    (SELECT CONCAT('%、', role_id, '、%' ) as  role_id_new FROM ${`userInfo`} WHERE user_id=?);`
    
    const sql_paramters = [user_id]
    dbConfig.sqlConnect(sql_check, sql_paramters, (err, data) => {
      if(err) {
        console.log(JSON.stringify(err))
        err_reply('actionPermissions',res,'按钮权限查询失败')
        reslove([false, err])
      } else {
        reslove([true, data])
      }
    })
  })
}

/** 
 * @description 5、菜单排序
 * */ 
const menu_srot = async function (req, res, next) {
   // 1、校验登录状态
   const validateLogin = await validateLoginState(res, req, 'post', 'menu_srot')

   if (!validateLogin) return
 
   // 得到对象数组，后续按照数组内的顺序，重新生成menu_type
   const list = req.body.list

   // 2、在保证当前数组内元素顺序不变的情况下，重新生成menu_type
  const data_after = sortDefault(list, 'children', 'menu_type')

  // 3、对data_after数组，按照children属性进行拆分出来（方便后面的 data_last.forEach）
  const data_last = flattenTree(data_after)
  // console.log('拆分后打印:', JSON.stringify(data_last))

  // 4、生成values，格式如下：
  /**
   * [
      ['"用户介绍'","'/layoutView/user'",0,"'1'",'NOW()',10001],
      ["'系统管理'","'/sys'",0,"'2'",'NOW()',10003],
     ]
   */
  let values = []
  data_last.forEach((element) => {
    // menu表，insert操作必填字段：menu_name、tag、parent_id、menu_type、create_time、id
    values.push([`'${element.menu_name}'`,`'${element.tag}'`, element.parent_id ?? 0,`'${element.menu_type}'`, 'NOW()', element.id])
  })

  // 5、生成condition
  /**
   * condition（字符串类型）最终格式如下：
   * ('用户介绍','/layoutView/user',0,'1',NOW(),10001),('系统管理','/sys',0,'2',NOW(),10003)
   */
  let condition = ''
  values.forEach((item, index) => {
    condition = condition + '(' + item.toString() + ')'
    if (index !== (values.length -1)) {
      condition += ','
    }
  })

  // 6、生成最终SQL语句
  const sql_thing = `INSERT INTO ${`menu`}(menu_name, tag, parent_id, menu_type, create_time, id) 
  VALUES ${condition} ON DUPLICATE KEY UPDATE menu_name = VALUES(menu_name), tag = VALUES(tag),
  parent_id = VALUES(parent_id), menu_type = VALUES(menu_type), create_time = VALUES(create_time)`
  
  // 7、访问数据库，进行更新
  dbconfig.sqlConnect(sql_thing, [], (err, data) => {
    if(err) {
      console.log(`菜单排序 - 事物SQL，执行出错！`)
      console.log(err)
      err_reply('menu/srot', res, '排序请求出错了')
    } else {
      console.log(`菜单排序 - 事物SQL，执行成功！`)
      success_reply('menu/srot', res, '排序请求成功！')
    }
  })
}

module.exports = { menu_add, menu_delete, menu_update, menu_query, menu_srot }